﻿package com.riatimes.net.socket
{
	import com.adobe.crypto.MD5;
	import com.carlcalderon.arthropod.Debug;
	import com.riatimes.event.SocketEvent;
	import com.riatimes.util.Logger;
	
	import flash.events.*;
	import flash.utils.*;
	
	import org.puremvc.as3.patterns.observer.Notifier;
	


    /**
     * Socket数据处理类
     * @author Nick Wong
     */
    public class GameData extends Notifier
    {
        /**
         * 
         * 接收的字节 
         */
        public var revBytes:ByteArray;
        /**
         * 
         * md5验证key 
         */
        public static var key2:String = "mykey1#@!";
        /**
         * 
         * 异或加密key 
         */
        public static var key:String = "mykey2!@#";

        /**
         * 构造函数
         */
        public function GameData()
        {
            revBytes = new ByteArray();

        }

        /**
         * 解包
         * @param inBytes
         * @return 
         */
        public function UnEncapsulation(inBytes:ByteArray) : int
        {
            var unRev:int;
            var myHead:ByteArray;
            var dataLength:uint;
            //var userId:String=ModelLocator.getInstance().userId;
            var dataType:uint;
            var cmd:uint;
            var msgLength:int;
            var myContent:ByteArray;
            var dataContent:String;
            var myTail:ByteArray;
            var tail:String;
            var testMd5:String;
			
			
            var bytes:ByteArray = inBytes;
			bytes.endian = Endian.LITTLE_ENDIAN;
			
			
			/*var topHead:ByteArray=new ByteArray();
			inBytes.position = 0;
			inBytes.endian = Endian.LITTLE_ENDIAN;
			
			inBytes.readBytes(topHead, 0, 4);
			topHead.endian = Endian.LITTLE_ENDIAN;
			topHead.position = 0;
			var totalLenght:uint=topHead.readUnsignedInt();
			var bytes:ByteArray=new ByteArray();
			inBytes.readBytes(bytes, 0, (totalLenght));
			
			bytes.position = 0;
			bytes.uncompress();*/
			
			
			
            try
            {
                bytes.position = 0;
                myHead = new ByteArray();
                bytes.readBytes(myHead, 0, 8);
                myHead.endian = Endian.LITTLE_ENDIAN;
                myHead.position = 0;
                dataLength = myHead.readUnsignedInt();
                //userId = myHead.readDouble();
                cmd=myHead.readUnsignedInt();
				//dataType = myHead.readUnsignedInt();
                msgLength = dataLength-40;
                unRev = bytes.length - dataLength;
                Logger.logInfo(dataLength, cmd);
				
				
				myTail = new ByteArray();
				bytes.readBytes(myTail, 0, 32);
				myTail.position = 0;
				tail = myTail.readUTFBytes(myTail.length);
				
                myContent = new ByteArray();
                bytes.readBytes(myContent, 0, msgLength);
                myContent = Decrypt(myContent, GameData.key);
                myContent.position = 0;
                dataContent = myContent.readUTFBytes(msgLength);
				
				Logger.logInfo(dataContent);
                testMd5 = MD5.hash( dataContent + GameData.key2);
                if (testMd5.toLocaleLowerCase() != tail.toLocaleLowerCase())
                {
                    Logger.logError("数据包是非法的");
                    //dispatchEvent(new GameDataEvent(GameDataEvent.UNUSEDATA));
					sendNotification(SocketEvent.EVENT_UNUSEDATA);
                    return unRev;
                }
                //dispatchEvent(new GameDataEvent(GameDataEvent.GETDATA, cmd, dataContent));
				//发送解包后的数据，cmd为命令号，data为内容体
				sendNotification(SocketEvent.EVENT_GETDATA, {"cmd":cmd,"data":dataContent } );
            }
            catch (e:Error)
            {
				
                //dispatchEvent(new GameDataEvent(GameDataEvent.UNUSEDATA));
				Logger.logError(e.message);
				Logger.logError(cmd,dataContent);
				//捕获错误
				sendNotification(SocketEvent.EVENT_UNUSEDATA);
            }
            return unRev;
        }

        /**
         * 设置内容
         * @param data
         * @return 
         */
        public function setDataContent(data:String) : ByteArray
        {

            var bytes:ByteArray = new ByteArray();
            bytes.writeUTFBytes(data);
            return Encrypt(bytes, GameData.key);
        }

        /**
         * 设置包头数据
         * @param dataLen
         * @param cmd
         * @param type
         * @return 
         */
        public function setDataHead(dataLen:uint,cmd:uint, type:uint = 0) : ByteArray
        {
            var bytes:ByteArray = new ByteArray();
            bytes.endian = Endian.LITTLE_ENDIAN;
            bytes.writeUnsignedInt(dataLen);
            //bytes.writeDouble(userId);
            bytes.writeUnsignedInt(cmd);
            //bytes.writeUnsignedInt(type);
            return bytes;
        }

        /**
         * 设置尾部验证数据
         * @param data
         * @param userId
         * @param cmd
         * @param type
         * @param info
         * @return 
         */
        public function setDataTail(data:String, userId:String, cmd:uint, type:uint,info:uint=0) : ByteArray
        {
            var hashStr:String = null;
            var bytes:ByteArray = null;
			//hashStr = MD5.hash(userId.toString() + cmd.toString() + type.toString() + info.toString()+ data + GameData.key2);
			hashStr = MD5.hash( data + GameData.key2);
			//Logger.logInfo(data,GameData.key2,hashStr);
            bytes = new ByteArray();
            bytes.writeUTFBytes(hashStr);
            return bytes;
        }

        /**
         * 打包操作
         * @param cmd
         * @param data
         * @return 
         */
        public function Encapsulation(cmd:uint, data:String) : ByteArray
        {
            var bytes:ByteArray = null;
            var dataBytes:ByteArray = null;
            var headBytes:ByteArray = null;
            var tailBytes:ByteArray = null;
			
			
            bytes = new ByteArray();
			bytes.endian = Endian.LITTLE_ENDIAN;
            dataBytes = setDataContent(data);
			Logger.logInfo("dataBytes.length",dataBytes.length);
			
			
            headBytes = setDataHead((dataBytes.length+40),cmd);
            tailBytes = setDataTail(data, "", cmd, 0);
            headBytes.position = 0;
            headBytes.readBytes(bytes, 0, headBytes.length);
			tailBytes.position = 0;
			tailBytes.readBytes(bytes, headBytes.length, tailBytes.length);
            dataBytes.position = 0;
            dataBytes.readBytes(bytes, (headBytes.length+tailBytes.length), dataBytes.length);
            
            
			return bytes;
			/*
			bytes.position = 0;			
			Logger.logInfo("dataBytes.length:"+dataBytes.length);
            bytes.compress();
			
			var myBytes:ByteArray=new ByteArray();
			myBytes.endian = Endian.LITTLE_ENDIAN;
			myBytes.writeUnsignedInt(bytes.length);
			Logger.logInfo("bytes.length",bytes.length);
			bytes.position = 0;
			bytes.readBytes(myBytes,myBytes.length,bytes.length);
            return myBytes;*/
        }

        /**
         * 解密字节数据
         * @param bytes
         * @param key
         * @return 
         */
        public function Decrypt(bytes:ByteArray, key:String) : ByteArray
        {
            return Encrypt(bytes, key);
        }

        /**
         * 加密字节内容
         * @param bytes
         * @param key
         * @return 
         */
        public function Encrypt(bytes:ByteArray, key:String) : ByteArray
        {
			
			return bytes;
            var i:int;
            var len:int;
            var byteKey:ByteArray;
            var klen:int;
            var t:int;
            var pToEncrypt:ByteArray = bytes;
            var key:String = key;
            try
            {
                len = pToEncrypt.length;
                byteKey = new ByteArray();
                byteKey.writeUTFBytes(key);
                klen = byteKey.length;
                if (klen == 0)
                {
                    byteKey.writeUTFBytes("sswe2234sd!@$df");
                }
                while (i < len)
                {
                    t = i % klen;
                    pToEncrypt[i] = pToEncrypt[i] ^ byteKey[t];
                    i = (i + 1);
                }
            }
            catch (e:Error)
            {
                trace("加密失败");
            }
            return pToEncrypt;
        }

        /**
         * 接收socket消息
         * @param bytes
         */
        public function RevNetMessage(bytes:ByteArray) : void
        {
            var buffer:ByteArray;
            var unRev:int;
            var revBuf:ByteArray;
            var bytes:ByteArray = bytes;
            try
            {
                buffer = new ByteArray();
                if (revBytes.length > 0 && revBytes.position > 0)
                {
                    trace("与缓冲区中的数据合并");
                    revBytes.writeBytes(bytes);
                    buffer.writeBytes(revBytes);
                    revBytes = new ByteArray();
                }
                else
                {
                    buffer.writeBytes(bytes);
                }
                unRev = UnEncapsulation(buffer);
                while (unRev > 0)
                {
                    
                    trace("处理粘包，剩余数据长度" + unRev);
                    revBuf = new ByteArray();
                    revBuf.writeBytes(buffer, buffer.length - unRev, unRev);
                    unRev = UnEncapsulation(revBuf);
                    buffer = revBuf;
                    if (unRev < 0)
                    {
                        trace("不是完整数据包，放入缓冲区！");
                        revBytes.writeBytes(buffer);
                    }
                }
            }
            catch (e:Error)
            {
                //dispatchEvent(new GameDataEvent(GameDataEvent.UNUSEDATA));
				sendNotification(SocketEvent.EVENT_UNUSEDATA);
            }
            return;
        }

    }
}
